<?php 

/**
 * 容器,也称服务容器,简称(IOC)
 * 基本思想:就是拿来就用,最大限度的简化外部对象的调用,类似于:[即插即用]的思想
 * 基本实现分三步:
 * 1.创建容器,将类与类的实例化过程绑定到容器中(不局限于类,也可是接口或其它)
 * 2.服务注册,将可能用到的工具类全部绑定到容器中
 * 3.容器依赖:或者叫依赖容器,调用工作类时直接传入容器对象即可,工具类的实例化由容器完成
 */


//数据库操作类
class Db
{
	//数据库连接
	public function connect()
	{
		return '数据库连接成功<br>';
	}
}

//数据验证类
class Validate
{
	//数据验证
	public function check()
	{
		return '数据验证成功<br>';
	}
}

//视图图
class View
{
	//内容输出
	public function display()
	{
		return '用户登录成功';
	}
}

/******************************************************************************/

//一.创建容器类
class Container
{
	//创建属性,用空数组初始化,该属性用来保存类与类的实例化方法
	protected $instance = [];

	//初始化实例数组,将需要实例化的类,与实例化的方法进行绑定
	public function bind($abstract, Closure $process)
	{
		//键名为类名,值为实例化的方法
		$this->instance[$abstract] = $process;
	}

	//创建类实例
	public function make($abstract, $params=[])
	{
		return call_user_func_array($this->instance[$abstract],[]);
	}

}

/******************************************************************************/

//二、服务绑定: 将类实例注册到容器中
$container = new Container(); 

//将Db类绑定到容器中
$container->bind('db', function(){
	return new Db();
});

//将Validate类实例绑定到容器中
$container->bind('validate', function(){
	return new Validate();
});

//将View类实例绑定到容器中
$container->bind('view', function(){
	return new View();
});

//测试:查看一下当前容器中的类实例
// var_dump($container->instance); die;

/******************************************************************************/

//三、容器依赖:将容器对象,以参数的方式注入到当前工作类中

//用户类:工作类
class User
{
	//创建三个成员属性,用来保存本类所依赖的对象
	// protected $db = null;
	// protected $validate = null;
	// protected $view = '';
	//这三个与外部对象对应的三个属性可以全部删除了,因为它们都已经事先注册到了容器中

	//用户登录操作
	// public function login(Db $db, Validate $validate, View $view)
	//此时,只需从外部注入一个容器对象即可,Db,Validate和View实例方法全部封装到了容器中
	public function login(Container $container)
	{
		//实例化Db类并调用connect()连接数据库
		// $db = new Db();
		// echo $db->connect();
		echo $container->make('db')->connect();

		//实例化Validate类并调用check()进行数据验证
		// $validate = new Validate();
		// echo $validate->check();
		echo $container->make('validate')->check();

		//实例化视图类并调用display()显示运行结果
		// $view = new View();
		echo $container->make('view')->display();
	}
}
//在客户端完成工具类的实例化(即工具类实例化前移)
// $db = new Db();
// $validate = new Validate();
// $view = new View();

//现在注入过程就非常简单了,只需要从外部注入一个容器对象即可

//创建User类
$user = new User();

//调用User对象的login方法进行登录操作
// echo $user->login();
// 将该类依赖的外部对象以参数方式注入到当前方法中,当然,推荐以构造器方式注入最方便
echo '<h3>用依赖容器进行解藕:</h3>';
// echo $user->login($db, $validate, $view);
//现在工作类中的login方法不需要再像对象依赖注入那样写三个对象了,只需要一个容器对象就可以了
echo $user->login($container);












